#pragma once
#include "crypto/algorithms/ialgorithm/FAQCipherAlgorithm.h"
#include "crypto/algorithms/ialgorithm/FAQBlockAlgorithm.h"
#include "crypto/algorithms/ialgorithm/FAQKeyAlgorithm.h"

namespace yzrilyzr_crypto{
	static int32_t toUnsignedInt(int8_t by){
		return static_cast<int32_t>(by) & 0xFF;
	}
	EBCLASS(KeyExpander){
	public:
	int32_t nk; // number of 32-bit words in the key
	int32_t nr; // number of rounds
	yzrilyzr_array::Array<yzrilyzr_array::ByteArray> keys;
	public:
	KeyExpander(const yzrilyzr_array::ByteArray & key);
	~KeyExpander()=default;
	private:
	void keyExpansion(const yzrilyzr_array::ByteArray & initialKey);
	void keyExpansionCore(const yzrilyzr_array::ByteArray & in, int32_t round);
	};
	EBCLASS(State){
	public:
	yzrilyzr_array::ByteArray data;
	yzrilyzr_array::Array<yzrilyzr_array::ByteArray> keys;
	int32_t round;
	int32_t rounds;
	public:
	State();
	~State()=default;
	void setKey(const KeyExpander & ke);
	void input(const yzrilyzr_array::ByteArray & data);
	void apply(const yzrilyzr_array::ByteArray & data);
	const yzrilyzr_array::ByteArray getKey(int32_t i);
	yzrilyzr_array::ByteArray getData();
	void addRoundKey(const yzrilyzr_array::ByteArray & key);
	void subBytes();
	void InverseSubBytes();
	void shiftRows();
	void InverseShiftRows();
	void mixColumns();
	void InverseMixColumns();
	};
	ECLASS(Rijndael, public FAQCipherAlgorithm, public FAQBlockAlgorithm, public FAQKeyAlgorithm){
	public:
	Rijndael()=default;

	private:
	State state;
	public:
		/* 加密 */
	yzrilyzr_array::ByteArray encrypt(const yzrilyzr_array::ByteArray & in) override;

	/* 解密 */
	yzrilyzr_array::ByteArray decrypt(const yzrilyzr_array::ByteArray & in) override;

	private:
	void decryptCore();
	void encryptCore();

	public:
	void setKey(const FAQKey & rawKey) override;
	void setKey(const yzrilyzr_array::ByteArray & rawKey);

	u_index getBlockSize() const override{
		return 16;
	}

	yzrilyzr_lang::String getAlgorithmName() const override{
		return "Rijndael";
	}

	std::shared_ptr<FAQAlgorithm> newInstance() const override{
		return std::static_pointer_cast<FAQAlgorithm>(std::make_shared<Rijndael>());
	}

	};
}